﻿using System;
using System.ComponentModel;
using Utils;

namespace StockAccessors.Interdin.Engine
{
	internal class AccessorInformation : PropertyChangedNotifier, IStockDataAccessorInformation
	{
		#region Attributes

		private readonly AccessorEngine _engine;
		private readonly FuturesPageReader _futuresPageReader;
		private readonly CfdPageReader _cfdPageReader;

		private DateTime? _lastDataReceived;

		#endregion

		#region Properties

		public bool Connected
		{
			get
			{
				return _engine.Connected;
			}
		}

		public int Reconnections
		{
			get
			{
				return _engine.Reconnections;
			}
		}

		public int ReadCycles
		{
			get
			{
				// We're aware that can be race conditions here but we don't care as is it just information for the UI and does not need to be exact data.
				return _futuresPageReader.PagesRead + _cfdPageReader.PagesRead;
			}
		}

		public DateTime? LastDataReceived
		{
			get
			{
				return _lastDataReceived;
			}
		}

		public bool InvalidConnectionData
		{
			get
			{
				return _engine.InvalidConnectionData;
			}
		}

		#endregion

		#region Public Methods

		internal AccessorInformation(AccessorEngine engine, FuturesPageReader futuresPageReader, CfdPageReader cfdPageReader)
		{
			_engine = engine;
			_futuresPageReader = futuresPageReader;
			_cfdPageReader = cfdPageReader;

			_engine.PropertyChanged += this.Engine_PropertyChanged; // Disposed
			_futuresPageReader.PropertyChanged += this.FuturePageReader_PropertyChanged; // Disposed
			_cfdPageReader.PropertyChanged += this.CdfPageReader_PropertyChanged; // Disposed
		}

		#endregion

		#region Event Handlers

		private void Engine_PropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			base.OnPropertyChangedAsync(e.PropertyName);
		}

		private void FuturePageReader_PropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			if (e.PropertyName == "PagesRead")
			{
				_lastDataReceived = DateTime.Now;
				base.OnPropertyChangedAsync("ReadCycles");
				base.OnPropertyChangedAsync("LastDataReceived");
			}
		}

		private void CdfPageReader_PropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			if (e.PropertyName == "PagesRead")
			{
				_lastDataReceived = DateTime.Now;
				base.OnPropertyChangedAsync("ReadCycles");
				base.OnPropertyChangedAsync("LastDataReceived");
			}
		}

		#endregion

		#region IDisposable

		protected bool Disposed { get; private set; }

		private void Dispose(bool disposing)
		{
			if (!this.Disposed)
			{
				this.InternalDispose(disposing);
			}

			this.Disposed = true;
		}

		protected virtual void InternalDispose(bool disposing)
		{
			if (disposing)
			{
				_engine.PropertyChanged -= this.Engine_PropertyChanged;
				_futuresPageReader.PropertyChanged -= this.FuturePageReader_PropertyChanged;
				_cfdPageReader.PropertyChanged -= this.CdfPageReader_PropertyChanged;
			}

			// Dispose here only unmanaged objects 
			// Don’t use managed objects here because maybe 
			// they have been finalized already
		}

		public void Dispose()
		{
			this.Dispose(true);
			GC.SuppressFinalize(this);
		}

		~AccessorInformation()
		{
			this.Dispose(false);
		}

		#endregion
	}
}
